<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta
            name="viewport"
            content="width=device-width,initial-scale=1.0,user-scalable=0"
        />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <meta name="description" content="一个简单的舒尔特训练工具" />
        <meta name="keywords" content="舒尔特,舒尔特训练,舒尔特方格" />
        <title>舒尔特方格训练</title>
        <style type="text/css">
            body {
                padding: 0;
                margin: 0;
            }

            .title {
                font-size: 18px;
                font-weight: bold;
                color: #000;
                text-align: center;
                padding: 50px 0;
            }

            .game-container {
                display: flex;
                flex-wrap: wrap;
                width: 90%;
                margin: 0 auto;
                box-sizing: border-box;
                border-top: 1px solid #999;
                border-left: 1px solid #999;
            }

            .game-container .game-block {
                box-sizing: border-box;
                position: relative;
                border-right: 1px solid #999;
                border-bottom: 1px solid #999;
            }



            .game-container .game-block .content {
                position: absolute;
                width: 100%;
                height: 100%;
                display: flex;
                align-items: center;
                justify-content: center;
                font-size: 18px;
                font-weight: bold;
            }

            .game-container .game-block.change .content {
                animation: animate-word 1s linear 1;
            }

            .game-container .game-block::after {
                content: "";
                display: block;
                padding-bottom: 100%;
            }

            .game-functions {
                display: flex;
                justify-content: center;
                align-items: center;
                padding: 20px 0;
            }

            .game-func-block {
                display: flex;
                flex-direction: column;
                align-items: center;
                justify-content: center;
                padding: 10px 20px;
            }

            .game-func-block .label {
                font-size: 14px;
                color: #999;
                margin-bottom: 5px;
            }

            .level-selector {
                width: 60px;
                height: 30px;
            }

            .btn {
                font-size: 14px;
                padding: 5px 20px;
                border-radius: 4px;
                border: 1px solid #f5f5f5;
                box-shadow: 0 2px 2px #666;
                color: #fff;
                transition: all ease 0.5s;
            }

            .btn.yellow {
                background: #b49c27;
            }

            .btn.green {
                background: #0e9595;
            }

            .btn.red {
                background: #d54c4c;
            }

            .btn:hover {
                color: #eee;
            }

            .btn:active {
                color: #eee;
                box-shadow: 0 2px 2px #333;
                transform: scale(1.5);
                -o-transform: scale(1.5);
                -moz-transform: scale(1.5);
                -webkit-transform: scale(1.5);
            }

            .time-recoder {
                display: flex;
                align-items: center;
                justify-content: center;
                flex-direction: column-reverse;
            }

            .time-item {
                font-size: 18px;
                margin-top: 4px;
            }

            .clear-time {
                color: #0e9595;
                font-size: 12px;
            }

            .clear-time:active {
                color: #064141;
            }

            .grid-description {
                position: fixed;
                top: -120%;
                left: 10%;
                background: #fefefe;
                box-sizing: border-box;
                color: #666;
                border-radius: 5px;
                padding: 10px;
                margin: 0 auto;
                width: 80%;
                font-size: 13px;
                max-height: 500px;
                overflow: auto;
                box-shadow: 2px 2px 10px #999;
                transition: all ease 0.5s;
                z-index: 20;
            }

            .grid-description p {
                margin: 0;
                padding: 5px 0;
            }

            .grid-description.show {
                top: 30px;
            }

            .grid-description a {
                color: #0e9595;
            }

            .grid-description-overlay {
                position: fixed;
                top: 0;
                left: 0;
                right: 0;
                bottom: 0;
                background: rgba(0, 0, 0, 0.4);
                display: none;
                z-index: 10;
            }

            .grid-description-overlay.show {
                display: block;
            }

            .grid-description-trigger {
                color: #0e9595;
                font-size: 12px;
                border-bottom: 1px solid #999;
                position: fixed;
                bottom: 10px;
                right: 10px;
                background: #fefefe;
                padding: 4px 8px;
                border-radius: 5px;
            }

            .grid-description-trigger:active {
                color: rgb(21, 37, 65);
            }

            @keyframes animate-word {
                0% {
                    opacity: 0;
                }
                20% {
                    opacity: 0.4;
                }
                40% {
                    opacity: 0.6;
                }
                60% {
                    opacity: 0.8;
                }
                80% {
                    opacity: 0.9;
                }
                100% {
                    opacity: 1;
                }
            }
        </style>
    </head>
    <body>
        <div id="app">
            <div class="title">舒尔特方格训练</div>
            <div class="game-container">
                <div
                    :class="[{change: isChanging}, 'game-block']"
                    :style="{width: 'calc(100% / ' + level + ')'}"
                    v-for="block in blocks"
                >
                    <div class="content">
                        {{ block }}
                    </div>
                </div>
            </div>
            <div class="game-functions">
                <div class="game-func-block">
                    <div class="wrapper" @click="shuffle">
                        <div class="btn yellow">刷新</div>
                    </div>
                </div>

                <div class="game-func-block">
                    <div class="wrapper">
                        <select
                            class="level-selector"
                            v-model="level"
                            @change="shuffle"
                        >
                            <option value="2">2</option>
                            <option value="3">3</option>
                            <option value="4">4</option>
                            <option value="5">5</option>
                            <option value="6">6</option>
                            <option value="7">7</option>
                            <option value="8">8</option>
                        </select>
                    </div>
                </div>

                <div class="game-func-block" @click="toggle">
                    <div class="wrapper">
                        <div
                            :class="[{'red' : isRunning, 'green': !isRunning}, 'btn']"
                        >
                            {{ isRunning ? "结束" : "开始" }}
                        </div>
                    </div>
                </div>
            </div>

            <div class="time-recoder">
                <div class="time-item" v-for="time in timers">
                    {{ formatTime(time) }}
                </div>
                <div class="clear-time" v-if="timers.length" @click="cleanTime">
                    清除时间
                </div>
            </div>

            <div class="grid-description-trigger" @click="toggleDescription">
                舒尔特方格介绍
            </div>

            <div
                :class="[{'show' : isShowDesc}, 'grid-description-overlay']"
                @click="toggleDescription"
            ></div>

            <div :class="[{'show' : isShowDesc}, 'grid-description']">
                <p>
                    舒尔特方格 (Schulte Grid) 是在一张方形卡片上画上 1cm*1cm 的
                    25 个方格，格子内任意填写上阿拉伯数字 1 ~ 25 等共 25
                    个数字。训练时，要求被测者用手指按 1 ~ 25
                    的顺序依次指出其位置，同时诵读出声，施测者一旁记录所用时间。数完
                    25 个数字所用时间越短，注意力水平越高。
                </p>
                <p>
                    以 7—12 岁年龄组为例
                </p>
                <ul>
                    <li>26秒及以内为优秀，学习成绩应是名列前茅</li>
                    <li>42秒属于中等水平，班级排名会在中游或偏下</li>
                    <li>50秒则问题较大，考试会出现不及格现象</li>
                </ul>
                <p>以 12―14岁年龄组为例</p>
                <ul>
                    <li>16秒及以内为优良，学习成就应是名列前茅</li>
                    <li>26秒属于中等水平，班级排名会在中游或偏下</li>
                    <li>36秒则问题较大，测验会呈现不合格现象</li>
                </ul>
                <p>18 岁及以上成年人</p>
                <ul>
                    <li>最好可到达8秒的程度</li>
                    <li>20秒为中等程度</li>
                </ul>
                <p>
                    舒尔特方格是全世界范围内最简单，最有效也是最科学的注意力训练方法。寻找目标数字时，注意力是需要极度集中的，把这短暂的高强度的集中精力过程反复练习，大脑的集中注意力功能就会不断的加固，提高。注意水平越来越高。
                </p>
                <p>
                    以上内容来自<a
                        href="https://baike.baidu.com/item/舒尔特方格/5372437"
                        >百度百科</a
                    >
                </p>
            </div>
        </div>

        <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
        <script type="text/javascript">
            Array.prototype.shuffle = function() {
                this.sort(() => 0.5 - Math.random());
            };

            new Vue({
                el: "#app",
                data: {
                    level: 5,
                    blocks: [],
                    isRunning: false,
                    isChanging: false,
                    isShowDesc: false,
                    timerInterval: null,
                    timers: []
                },
                mounted() {
                    this.shuffle();
                },
                methods: {
                    shuffle() {
                        let blocks = [],
                            that = this;
                        this.isChanging = true;
                        for (var i = 1; i <= this.level * this.level; i++) {
                            blocks.push(i);
                        }
                        blocks.shuffle();
                        this.blocks = blocks;
                        setTimeout(() => {
                            that.isChanging = false;
                        }, 500);
                    },
                    toggle() {
                        let that = this;
                        this.isRunning = !this.isRunning;
                        if (this.isRunning) {
                            this.timers.push(0);
                            let index = this.timers.length - 1;
                            this.timerInterval = setInterval(function() {
                                that.$set(
                                    that.timers,
                                    index,
                                    that.timers[index] + 1
                                );
                            }, 10);
                        } else {
                            this.timerInterval &&
                                clearInterval(this.timerInterval);
                        }
                    },
                    formatTime(time) {
                        let minutes = parseInt(time / 6000);
                        let seconds = parseInt((time - minutes * 6000) / 100);
                        let millSeconds = time % 100;
                        return `${minutes} 分 ${seconds} 秒 ${millSeconds}`;
                    },
                    toggleDescription() {
                        this.isShowDesc = !this.isShowDesc;
                    },
                    cleanTime() {
                        this.timerInterval && clearInterval(this.timerInterval);
                        if (this.isRunning) {
                            this.isRunning = !this.isRunning;
                        }
                        this.$set(this, "timers", []);
                    }
                }
            });
        </script>
    </body>
</html>
